#ifndef AST_Query_GUARD
#define AST_Query_GUARD

#include "../../SPA_Data_Types.h"
#include "AST_XLab2.h"
#include <stack>

using namespace std;

class AST_Query {
private:
	AST *_ast;
	typedef struct Query_state {
		INTEGER currProcPosition;
		procNode *currProc;
		stmtNode *firstStmtNode;
		stmtNode *currStmtNode;
		stmtNode *lastStmtNode;
	} Query_state;
	Query_state _state;
	stack<Query_state> _State_stack;

public:
	AST_Query( AST *ast);

	void resetAST_Query() {
		_state.currStmtNode = _ast->StmtAt(0);
	};

	INDEX getFirstStmtID ();
	INDEX getLastStmtID ();

	PROC_INDEX getCurrProcID (); // return INVALID_INDEX if no current proc exists.
	INTEGER numProcs ();
	INTEGER numStmts ();

	STATEMENT_TYPE getCurrStmtType();

	INDEX getCurrStmtIndex();

	INDEX* getLinksId();

	// procedure tarversal APIs
	STATUS gotoProcAt ( PROC_INDEX id );
	STATUS gotoStmtAt ( STATEMENT_INDEX id );


	// statement specific APIs...
	expr* getLHS () {
		if( _state.currStmtNode->getStmtType() != STATEMENT_Assign )
			return NULL;
		else 
			return ((assignment_stmtNode*)_state.currStmtNode)->getLHS();
	};

	expr* getRHS () {
		if( _state.currStmtNode->getStmtType() != STATEMENT_Assign )
			return NULL;
		else 
			return ((assignment_stmtNode*)_state.currStmtNode)->getRHS();
	}

	STRING getSyntacticExpr () {
		if( _state.currStmtNode->getStmtType() != STATEMENT_Assign )
			return NULL;
		else 
			return ((assignment_stmtNode*)_state.currStmtNode)->getSyntacticString();
	};

	PROC_INDEX getCallProcID () {
		if( _state.currStmtNode->getStmtType() != STATEMENT_Call )
			return -1;
		else 
			return(((call_stmtNode*)_state.currStmtNode)->getCallProcID());
	};

	VAR_INDEX getConditionVar () {
		if( _state.currStmtNode->getStmtType() != STATEMENT_While )
			return ((while_stmtNode*)_state.currStmtNode)->getConditionVar();
		else if( _state.currStmtNode->getStmtType() != STATEMENT_If )
			return ((if_stmtNode*)_state.currStmtNode)->getConditionVar();
		else 
			return -1;
	};

	// traversal APIs
	STATUS gotoNextLine ();
	STATUS gotoPrevLine ();
	STATUS gotoNext() {
		if (_state.currStmtNode->links[stmtNode::NEXT_STMT] == NULL) {
			return STATUS_Failure;
		} else {
			_state.currStmtNode = _state.currStmtNode->links[stmtNode::NEXT_STMT];
			return STATUS_Success;
		}
	};

	BOOLEAN gotoFollows() {
		if( _state.currStmtNode == NULL )
			return 0;
		else if(_state.currStmtNode->_nextNode == NULL )
			return 0;
		_state.currStmtNode = _state.currStmtNode->_followsNode;
		return 1;
	};

	void gotoParent() {
		cout << "parent relationships not implemented!!!  0= " << endl;
	};

	void gotoPrev() {
		cout << "reverse iteration not implemented!!!  0=" << endl;
	};

};

#endif